<template>
  <view class="map-content" :style="{ paddingTop: statusBarH + 'px', backgroundColor: '#fff', top: top + 'px'}">
    <map
      id="map"
      class="map"
      :latitude="lat"
      :longitude="long"
      scale="12"
      show-location
      enable-poi
      :polyline="polyline"
      :polygons="isPolygons ? polygons : []"
      :markers="selectedMarkers"
      @tap="(e) => { handleShowLocation(e, true); }"
      @poitap="handlePoiTap"
    >
      <view><slot name="content"></slot></view>
    </map>
    <view :style="{ height: `calc(50vh - ${statusBarH + 'px'} - ${top + 'px'} - env(safe-area-inset-bottom))` }">
      <view class="control-row d-flex j-sb px-3  pb-1 pt-2">
        <view class="cancel" @click="handleCancel">取消</view>
        <view class="confirm" @click="handleConfirm" :style="{ backgroundColor: disable ? '' : '#0052d9', color: disable ? '' : '#FFF' }">
          确认项目所在地
        </view>
      </view>
      <view class="search">
        <view class="search-input" style="width: 100%;">
          <input placeholder="搜索地点" v-model="searchValue" type="text" maxlength="64" @input="$u.debounce(getPoiSugestions, 500)" />
        </view>
        <view style="width: 100rpx; margin-left: 20rpx;">清空</view>
      </view>
      <scroll-view :scroll-x="false" :scroll-y="true" :style="{ height: `calc(50vh - ${statusBarH + 'px'} - ${top + 'px'} - env(safe-area-inset-bottom) - 90rpx - 80rpx)` }">
        <view class="bot-box" :class="{ 'mt-6' : searchList.length == 0 }">
          <view class="poi-list">
            <template v-if="searchList.length != 0">
              <view class="poi-item" v-for="(item, i) in searchList" :key="i" @click="handlePoiItemClick(item)">
                <view class="d-flex j-sb a-center">
                  <view>
                    <view class="poi-name">{{ item.title }}</view>
                    <view class="poi-address">
                      <view class="address" style="overflow: hidden; width: 600rpx;">
                        {{ item.address }}
                      </view>
                    </view>
                  </view>
                  <view style="color: #0052d9;" v-if="item.id === selectedPoidId"><u-icon name="checkbox-mark"></u-icon></view>
                </view>
              </view>
            </template>
            <u-empty v-if="searchList.length == 0" :icon="getStaticFilePath('empty/search.png')" text="暂无建议数据" />
          </view>
          <view style="height: 1px;"></view>
        </view>
      </scroll-view>
    </view>
  </view>
</template>

<script>
var QQMapWX = require('@/utils/qqmap-wx-jssdk.min.js');

class mapPlugin {
	/**
	 * 腾讯地图微信小程序API类
	 *
	 * @constructor
	 */
  constructor(param) {
    this.qqmapsdk = new QQMapWX({
      key: param['ak']
    });
  }

  /**
   * 使用微信接口进行定位
   *
   * @param {string} type 坐标类型
   * @param {Function} success 成功执行
   * @param {Function} fail 失败执行
   * @param {Function} complete 完成后执行
   */
  getLocation(type, success, fail, complete) {
    (type = type || 'gcj02'), 
    (success = success || function() {});
    fail = fail || function() {};
    complete = complete || function() {};
    wx.getLocation({
      type: type,
      success: success,
      fail: fail,
      complete: complete
    });
  }

  /**
   * sug模糊检索
   *
   * @param {Object} param 检索配置
   * 参数对象结构可以参考
   * https://apis.map.qq.com/ws/place/v1/search
   */
  execGetSuggestion(param) {
    var that = this;
    param = param || {};
    let params = {
      keyword: param['query'] || '',
    };
    
    let callbacks = {
      success: param['success'] || function() {},
      fail: param['fail'] || function(message) {
        console.log(message)
        uni.showToast({
          icon: 'none',
          title: message
        })
      }
    };
    this.qqmapsdk.getSuggestion({
      ...params,
      success: (data) => {
        if (data.status == 0) {
          callbacks.success(data);
        } else {
          callbacks.fail(data.message);
        }
      },
      fail: (err) => {
        callbacks.fail(JSON.stringify(err));
      }
    })
  }

  /**
   * rgc检索（逆地理编码：经纬度->地点描述）
   *
   * @param {Object} param 检索配置
   * 参数对象结构可以参考
   * https://apis.map.qq.com/ws/geocoder/v1/?location=
   *
   */
  execReverseGeocoding(param) {
    var that = this;
    param = param || {};
    let params = {
      location: param['location'] || {},
      coord_type: 5,
      get_poi: 1,
      poi_options: `address_format=short;radius=5000;policy=4/5`
    };
    let callbacks = {
      success: param['success'] || function() {},
      fail: param['fail'] || function(message) {
        uni.showToast({
          icon: 'none',
          title: message
        })
      }
    };
    let type = 'gcj02';
    
    //定位成功
    let handleLocateSuccess = function(result) {
      that.qqmapsdk.reverseGeocoder({
        ...params,
        success: (data) => {
          if (data.status == 0) {
            let poiObj = data.result;
            let outputRes = {};
            outputRes.originalData = data;
            outputRes.wxMarkerData = [];
            outputRes.wxMarkerData[0] = {
              id: data.request_id,
              latitude: poiObj.location.lat,
              longitude: poiObj.location.lng,
              address: poiObj.formatted_addresses.standard_address,
              desc: poiObj.formatted_addresses.recommend,
              
              iconPath: callbacks['iconPath'],
              iconTapPath: callbacks['iconTapPath'],
              alpha: callbacks['alpha'],
              width: callbacks['width'],
              height: callbacks['height']
            }
            callbacks.success(outputRes);
          } else {
            callbacks.fail(data.message);
          }
        },
        fail: (err) => {
          callbacks.fail(JSON.stringify(err));
        }
      })
    };
    //定位失败
    let handleLocateFail = function(result) {
      callbacks.fail(result);
    };
    //定位完成
    let handleLocateComplete = function(result) {};
    
    //业务逻辑
    if (!param['location']) {
      //如果参数里面没有携带定位数据参数，则调用微信的定位接口，获取到当前定位，
      that.getLocation(type, handleLocateSuccess, handleLocateFail, handleLocateComplete);
    } else {
      let longitude = param.location.longitude;
      let latitude = param.location.latitude;
      let errMsg = 'input location';
      let res = {
        errMsg: errMsg,
        latitude: latitude,
        longitude: longitude
      };
      handleLocateSuccess(res);
    }
  }
  /**
   * @description 规划路线
   * @param {Object} param
   */
  execDirection(param) {
    var that = this;
    param = param || {};
    let params = {
      mode: 'driving',
      from: param.from,
      to: param.to,
    }
    let callbacks = {
      success: param['success'] || function() {},
      fail: param['fail'] || function(message) {
        console.log(message)
        uni.showToast({
          icon: 'none',
          title: message
        })
      }
    };
    that.qqmapsdk.direction({
      ...params,
      success: (data) => {
        if (data.status == 0) {
          callbacks.success(data);
        } else {
          callbacks.fail(data.message);
        }
      },
      fail: (err) => {
        callbacks.fail(JSON.stringify(err));
      }
    })
  }
}

export default {
	name: 'bmap',
	props: {
		longitude: {
			type: String,
			default: ''
		},
		latitude: {
			type: String,
			default: ''
		},
    markerName: {
      type: String,
      default: ''
    },
		mapKey: {
			require: true,
			type: String,
			default: ''
		},
		marker: {
			type: Object,
			default: () => {}
		},
		disable: {
			type: Boolean,
			default: false
		},
		isPolygons: {
			type: Boolean,
			default: false
		},
		polygons: {
			type: Array,
			default: () => []
		},
		top: {
			type: [String, Number],
			default: 30
		},
		isCustomBar: {
			type: Boolean,
			default: false
		}
	},
	data() {
		return {
			statusBarH: 0,
			customBarH: 0,
			addressMap: this.$props?.markerName,
			searchValue: '',
			mapPlugin: null,
      key: this.$props?.mapKey,
      lat: this.$props?.latitude,
      long: this.$props?.longitude,
			regeocodeData: {},
			searchList: [],
      
      selectedPoidId: '', //当前点选的POIid
      polyline: [],
      mapInstance: null,
      userLat: '',
      userLong: '',
      selectedMarkers: [], //用户打的标记
		};
	},
  created() {
    this.init();
    let self = this;
    uni.getSystemInfo({
      success: function(e) {
        self.statusBarH = e.statusBarHeight + 17;
        if (uni.getMenuButtonBoundingClientRect?.()) {
          let custom = uni.getMenuButtonBoundingClientRect();
          self.customBarH = custom.height + 5;
        } else {
          self.customBarH = 30;
        }
      }
		});
	},
	methods: {
    /**
     * @description 初始化地图
     */
    init() {
      //初始化插件
      this.mapPlugin = new mapPlugin({
        ak: this.key, //APPKEY
      });
      const detail = {
        longitude: this.$props?.longitude,
        latitude: this.$props?.latitude
      };
      const _this = this;
      uni.getLocation({
        type: 'gcj02',
        isHighAccuracy: true,
        success: (data) => {
          //保存个人当前定位
          this.userLat = data.latitude;
          this.userLong = data.longitude;
          let args = {
            detail: {}
          };
          let showMarker = false;
          if (!detail.latitude || !detail.longitude) {
            args.detail.latitude = data.latitude;
            args.detail.longitude = data.longitude;
          } else {
            showMarker = true;
            args.detail.latitude = detail.latitude;
            args.detail.longitude = detail.longitude;
          }
          _this.handleShowLocation(args, showMarker);
        }
      });
      if (!this.mapInstance) {
        this.mapInstance = uni.createMapContext('map', this);
      }
    },
    
    /**
     * @description 地图点击事件
     * @param {Object} e
     */
    handleShowLocation(e, showMarker = false) {
      this.searchValue = '';
      const { latitude, longitude } = e.detail;
      if (!latitude || !longitude) return;
      this.getReverseGeoCodingResult(
        [longitude, latitude],
        (datas) => {
          this.searchList = datas;
          if (showMarker == true) {
            this.setMarker(latitude, longitude);
          }
        }
      );
    },
    
    /**
     * @description 获取搜索建议
     */
    getPoiSugestions() {
      if (!this.searchValue) return;
      this.mapPlugin.execGetSuggestion({
        query: this.searchValue,
        success: (data) => {
          this.searchList = data.data.filter(i => i?.id && i?.location);
        }
      });
    },
    
    /**
     * @description 获取指定坐标附近的POI数据
     * @param {Object} coords
     * @param {Object} fn
     */
    getReverseGeoCodingResult(coords, callback) {
      this.long = coords[0];
      this.lat = coords[1];
      this.mapPlugin.execReverseGeocoding({
        location: {
          latitude: this.lat,
          longitude: this.long
        },
        success: (data) => {
          const { result } = data.originalData;
          this.addressMap = result.formatted_addresses.standard_address;
          this.regeocodeData = result;
          this.$emit('changeMarker', this.getConfirmData());
          if (callback && typeof callback == 'function') {
            callback(result.pois);
          }
        }
      });
    },
    
    /**
     * @description 获取单个信息定位
     * @param {Object} data
     */
    handlePoiItemClick(data) {
      const { point, location } = data;
      this.searchValue = data.title;
      this.addressMap = data.address;
      this.selectedPoidId = data.id;
      this.getReverseGeoCodingResult(
        [point?.x || location.lng, point?.y || location.lat],
        (datas) => {
          this.searchList = datas;
        }
      );
      this.setMarker(point?.y || location.lat, point?.x || location.lng);
    },
    
    /**
     * @description 收集表单数据
     */
    getConfirmData() {
      const {
        pois,
        address_component: {
          province,
          city,
          district
        }
      } = this.regeocodeData;
      return {
        latitude: this.lat,
        longitude: this.long,
        address: this.addressMap
      };
    },
    
    /**
     * @description 提交定位信息
     * @param {Object} e
     */
    handleConfirm(e) {
      if (this.$props.disable) {
        return;
      }
      if (!this.addressMap) {
        return;
      }
      if (JSON.stringify(this.regeocodeData) != '{}') {
        this.$emit('confirm', this.getConfirmData());
      }
    },
    
    /**
     * @description 取消
     */
    handleCancel() {
      this.$emit('confirm');
    },
    
    /**
     * @description 打点
     * @param {Object} latitude
     * @param {Object} longitude
     */
    setMarker(latitude, longitude) {
      this.selectedMarkers = [];
      let contents = [];
      if (this.addressMap) {
        for (let i = 0; i < this.addressMap.length; i += 10) {
          contents.push(this.addressMap.substr(i, 10));
        }
      }
      let marker = {
        id: Math.floor(Math.random() * 1000000000),
        latitude: latitude,
        longitude: longitude,
        iconPath: this.getStaticFilePath('marker.png'),
        width: 29,
        height: 40,
        callout: {
          content: contents.join('\n'),
          bgColor: '#FFFFFF',
          padding: 6,
          borderRadius: 6,
          textAlign: 'center',
          fontSize: 12,
          color: '#0052d9',
          display: 'ALWAYS',
        }
      }
      this.selectedMarkers = [marker];
      this.polyline = [];
      this.$nextTick(() => {
        this.drawRoute(latitude, longitude);
      })
    },
    
    /**
     * @description 绘制行车路线
     * @param {Object} lat
     * @param {Object} long
     */
    drawRoute(lat, long) {
      let param = {
        from : {
          latitude: this.userLat,
          longitude: this.userLong
        },
        to: {
          latitude: lat,
          longitude: long
        },
        success: (datas) => {
          const route = datas.result.routes[0];
          var coors = route.polyline, pl = [];
          //坐标解压（返回的点串坐标，通过前向差分进行压缩）
          var kr = 1000000;
          for (var i = 2; i < coors.length; i++) {
            coors[i] = Number(coors[i - 2]) + Number(coors[i]) / kr;
          }
          //将解压后的坐标放入点串数组pl中
          for (var i = 0; i < coors.length; i += 2) {
            pl.push({ latitude: coors[i], longitude: coors[i + 1] })
          }
          this.polyline = [{
            points: pl,
            color: '#0052d9',
            width: 6,
            borderColor: '#003996',
            borderWidth: 1,
            arrowLine: true,
          }]
          this.$nextTick(() => {
            //调整视野
            this.mapInstance.includePoints({
              points: [
                {
                  latitude: this.userLat,
                  longitude: this.userLong
                },{
                  latitude: lat,
                  longitude: long
                },
                ...pl
              ],
              padding: [150, 100, 100, 100]
            })
          })
        }
      }
      this.mapPlugin.execDirection(param);
    },
    
    /**
     * @description 点击POI点位事件
     * @param {Object} e
     */
    handlePoiTap(e) {
    	this.handleShowLocation(e, true);
    },
  }
};
</script>

<style lang="scss" scoped>
.map-content {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 99;
  background-color: #fff;
  height: 100vh;
  width: 100vw;
  
  .control-row,
  .top {
    .cancel,
    .confirm {
      height: 60rpx;
      line-height: 1;
      padding: 0 30rpx;
      background-color: #F8F8F8;
      font-size: 28rpx;
      border-radius: 30rpx !important;
      display: flex;
      align-items: center;
    }
  }

	.top {
		position: absolute;
		width: 100%;
		height: 80rpx;
		display: flex;
		justify-content: space-between;
		align-items: center;
    padding: 10rpx 40rpx;
		box-sizing: border-box;
		background-color: rgba(0, 0, 0, 0.2);
		color: #fff;
		z-index: 999;
    
		.confirm {
			height: 60rpx;
			line-height: 1;
			padding: 0 30rpx;
			border-radius: 10rpx;
			background-color: #42b983;
      display: flex;
      align-items: center;
		}

		.address-text {
			width: 55vw;
			text-align: center;
			overflow: hidden;
			word-wrap: break-word;
			display: -webkit-box;
			-webkit-line-clamp: 1;
			-webkit-box-orient: vertical;
		}
	}

	.map {
    position: relative;
    width: 100vw;
    height: 50vh;
	}

	.search {
		padding: 10rpx 20rpx;
		display: flex;
		align-items: center;
		justify-content: space-between;
		background-color: #fff;

		input {
			// flex: 1;
			// width: calc(100vw - 80rpx);
			width: 100%;
			height: 64rpx;
			background: #f4f4f4;
			padding: 0 20rpx;
			height: 60rpx;
			border-radius: 14rpx;
		}
	}

	.bot-box {
		flex: 1;
		overflow: auto;
		width: 750rpx;
		background-color: #fff;

		.empty {
			margin-top: 40rpx;
			display: flex;
			align-items: center;
			justify-content: center;
		}

		.poi-list {
			padding: 0 $uni-spacing-row-base calc(0 + env(safe-area-inset-bottom)) $uni-spacing-row-base;
			box-sizing: border-box;
			width: 750rpx;
			.poi-item {
				// margin: 20rpx 0;
				padding: 20rpx;
				width: 680rpx;
				overflow: hidden;
				// border: 1px solid $uni-border-color;
				// border-radius: $uni-border-radius-base;

				.poi-name {
					font-size: 28rpx;
					color: #303133;
				}

				.poi-address {
					.address {
						width: 100%;
						font-size: 24rpx;
						overflow: hidden;
						color: #707070;
						white-space: nowrap;
						text-overflow: ellipsis;
					}
				}
			}
		}
	}
}
</style>
